package parserjc.jaccie;

import java.util.*;
import java.io.*;

/**
 * SICParserLL1 builds the parser frame for a LL(1) parser.
 * It implements the SICModuls to become a component of the
 * SIC structure.
 *
 * @author Volker Seibt
 * @version 1.00 09.1997
 */
public abstract class SICParserLL1 extends SICModule {

    /**
     * The grammar-rules the parser is based on.
     * Subclass have to set this rules to make the parser work.
     * (Use the 'ruleWithLookahead'-method).
     * Reihenfolge: String mit der linken Seite der Regel (Nichtterminal)
     *              Vector mit der Regel und der Lookahead-Menge als String[]
     */
    protected Vector sicRules = new Vector();

    /**
     * The grammar's startsymbol.
     * Subclasses have to set the startsymbol.
     */
    protected String startsymbol;

    protected SICParserInput sicPin = null;
    protected SICTree sicTree       = null;
    protected SICStack sicStack     = null;


    protected void ruleWithLookahead(String[] rule, String[] lookahead) {
        Vector tupel = new Vector(2);
        tupel.addElement(rule);
        tupel.addElement(lookahead);
        sicRules.addElement(rule[0]);
        sicRules.addElement(tupel);
    }

    // Public Instance Methods


    public final void setInput( SICParserInput pin ) {
        sicPin = pin;
    }

    public final void setInput( String[] pin ) {
        setInput(new SICParserInput(pin));
    }

    public final void setInput( String pinFileName ) throws IOException {
        setInput(new SICParserInput(pinFileName));
    }

    public final void setInput( File pinFile ) throws IOException {
        setInput(new SICParserInput(pinFile));
    }


    public final SICData getInput() {
        return sicPin;
    }


    public final boolean start( File pinFile ) throws IOException {
        return start(new SICParserInput(pinFile));
    }

    public final boolean start( String pinFileName ) throws IOException {
        return start(new SICParserInput(pinFileName));
    }

    public final boolean start( SICParserInput pin ) {
        setInput(pin);
        return start();
    }

    public final boolean start() {
        if ((sicPin==null) || (startsymbol == null) || sicRules.isEmpty()) {
            sicTree = null; sicStack = null;
            return false; }
          else {
            this.sicStack = new SICStack();
	    this.sicStack.push(0, new SICTree(startsymbol));
            this.sicTree = SICTree.newLeaf(this.startsymbol,null);
            int inputPosition = 0;

            String nextSymbol, topSymbol, nextValue;
            Vector ruleAndLookahead;
            boolean symbolInLookahead;
            String[] lookahead;

            while (true) {
                nextSymbol = ((SICTree)sicPin.elementAt(inputPosition)).getValue();
		nextValue  = 
                    (String)((SICTree)sicPin.elementAt(inputPosition)).getValueOfAttribute("string");

                if (nextSymbol.equals(SICParserInput.endElement.getValue()) &&
                    this.sicStack.isEmpty()) return true;

                topSymbol = this.sicStack.isEmpty()
                             ? "" : this.sicStack.peekTree().getValue();

                if (nextSymbol.equals(topSymbol)) {
                    // shift
                    if (nextValue != null)
                        ((SICTree)this.sicStack.pop().elementAt(1)).addAttribute(
                            "string","true",nextValue);
                    else this.sicStack.pop();
                    inputPosition++;
                }
                else {
                    Vector allLookaheads = get(topSymbol);
                    if (allLookaheads.size() == 0) return false;
                    boolean error=false;
                    for (int lookcount=0; lookcount<allLookaheads.size(); lookcount++) {
                        if (!error && (lookcount!=0)) break;
                        error = false;
                        ruleAndLookahead = (Vector)allLookaheads.elementAt(lookcount);
			if (ruleAndLookahead != null) {

                            symbolInLookahead = false;
                            lookahead = (String[])ruleAndLookahead.elementAt(1);

                            for (int i=0; i < lookahead.length; i++)
                                if (symbolInLookahead = nextSymbol.equals(lookahead[i]))
                                  break;
                            if (symbolInLookahead) {
                                // expand
                                this.sicTree.insertLeftMost(
                                    this.sicStack.expand(
                                       (String[])ruleAndLookahead.elementAt(0)));
                            }
                            else error=true;
                        }
                        else error=true;
                    }
                    if (error) return false;
                }
            }
        }
    }


    public final SICTree getResult() {
        return sicTree;
    }

    public final String getResultAsString() {
        if (sicTree==null) return null;
          else return sicTree.toString();
    }

    public final void saveResult( String einFileName ) throws IOException {
        saveResult(new File(einFileName));
    }

    public final void saveResult( File einFile ) throws IOException {
        if (sicTree!=null) sicTree.save(einFile);
    }

    public final SICStack getStack() {
        return sicStack;
    }


    //liefert einen Vector der m�glichen Vorschaumengen (als Vector)
    private Vector get(String nonT) {
        Vector retVector = new Vector();
        for (int i=0; i < sicRules.size()-1; i=i+2) {
            if (sicRules.elementAt(i).equals(nonT))
                retVector.addElement(sicRules.elementAt(i+1));
        }
        return retVector;
    }

}




